package com.example.designpattern.behavioral.visitor.pro;

import java.util.ArrayList;
import java.util.List;

class Restaurant {

    // 准备当天的食物
    private List<Food> prepareFoods() {
        List<Food> foods = new ArrayList<>();
        // 简单模拟，每种食物添加 10 份
        for (int i = 0; i < 10; i++) {
            foods.add(new Lobster());
            foods.add(new Watermelon());
            foods.add(new Steak());
            foods.add(new Banana());
        }
        return foods;
    }

    // 欢迎顾客来访
    public void welcome(IVisitor visitor) {
        // 获取当天的食物
        List<Food> foods = prepareFoods();
        // 将食物依次提供给顾客选择
        for (Food food : foods) {
            // 由于java是单分派机制，此处无法编译通过
//            visitor.chooseFood(food);

//            // 解决方案一：违背开闭原则
//            // 通过 instanceOf 判断具体子类型，再强制向下转型
//            if (food instanceof Lobster) visitor.chooseFood((Lobster) food);
//            else if (food instanceof Watermelon) visitor.chooseFood((Watermelon) food);
//            else if (food instanceof Steak) visitor.chooseFood((Steak) food);
//            else if (food instanceof Banana) visitor.chooseFood((Banana) food);
//            else throw new IllegalArgumentException("Unsupported type of food.");

            // 解决方案二
            /**
             * 用重写方法的动态分派特性将重载方法也模拟成动态分派。
             */
            // 由于重写方法是动态分派的，所以这里会调用具体子类的 accept 方法，
            food.accept(visitor);
        }
    }

    // 单分派和双重分派的区别就是：程序在选择重载方法和重写方法时，如果两种情况都是动态分派的，则称之为双重分派；如果其中一种情况是动态分派，另一种是静态分派，则称之为单分派。
}

